﻿using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Storage;

namespace Tax.DataAccess.Models
{
    public partial class TaxationContext : DbContext
    {
        public TaxationContext()
        {
        }

        public TaxationContext(DbContextOptions<TaxationContext> options)
            : base(options)
        {
            IsAuditingEnabled = true;
        }

        public virtual DbSet<City> City { get; set; }
        public virtual DbSet<TaxRate> TaxRate { get; set; }
        public virtual DbSet<User> User { get; set; }

        public bool IsAuditingEnabled { get; set; }

        public override int SaveChanges(bool acceptAllChangesOnSuccess)
        {
            int result;
            IDbContextTransaction tx = null;
            if (IsAuditingEnabled)
            {
                var entries = this.ChangeTracker.Entries();
                foreach (var entry in entries)
                {
                    setAuditingPropertyValues(entry);
                }
            }
            try
            {
                tx = base.Database.BeginTransaction();
                result = base.SaveChanges(acceptAllChangesOnSuccess);
                tx.Commit();
            }
            catch (Exception ex)
            {
                if (tx != null) tx.Rollback();
                throw ex;
            }
            return result;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
//#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
//                optionsBuilder.UseSqlServer("Data Source=.;Initial Catalog=Taxation;Persist Security Info=True; User ID=sa;Password=abc123!@#;");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.HasAnnotation("ProductVersion", "2.2.2-servicing-10034");

            modelBuilder.Entity<City>(entity =>
            {
                entity.HasIndex(e => e.CityCode)
                    .HasName("UQ_City_CityCode")
                    .IsUnique();

                entity.Property<int>("CityID").HasColumnName("CityID");

                entity.Property(e => e.AnnuityRate).HasColumnType("decimal(18, 2)");

                entity.Property(e => e.CityCode)
                    .IsRequired()
                    .HasMaxLength(16)
                    .IsUnicode(false);

                entity.Property(e => e.CityName)
                    .IsRequired()
                    .HasMaxLength(64);

                entity.Property(e => e.Deleted).HasDefaultValueSql("((0))");

                entity.Property(e => e.FundRate).HasColumnType("decimal(18, 2)");

                entity.Property(e => e.MedicareRate).HasColumnType("decimal(18, 2)");

                entity.Property(e => e.UnemployRate).HasColumnType("decimal(18, 2)");

                addAuditingProperties(entity);
            });

            modelBuilder.Entity<TaxRate>(entity =>
            {
                entity.Property<int>("TaxRateID").HasColumnName("TaxRateID");

                entity.Property(e => e.Deleted).HasDefaultValueSql("((0))");

                entity.Property(e => e.Rate).HasDefaultValueSql("((0))");

                entity.Property(e => e.Offset).HasDefaultValueSql("((0))");

                addAuditingProperties(entity);
            });

            modelBuilder.Entity<User>(entity =>
            {
                entity.HasIndex(e => new { e.LoginId, e.Deleted })
                    .HasName("UQ_City_LoginID_Deleted")
                    .IsUnique();

                entity.Property<int>("UserID").HasColumnName("UserID");

                entity.Property(e => e.Active).HasDefaultValueSql("((1))");

                entity.Property(e => e.DefaultQueryCityCode).HasColumnName("DefaultQueryCityCode");

                entity.Property(e => e.Deleted).HasDefaultValueSql("((0))");

                entity.Property(e => e.Email)
                    .IsRequired()
                    .HasMaxLength(64)
                    .HasDefaultValueSql("('')");

                entity.Property(e => e.FirstName)
                    .IsRequired()
                    .HasMaxLength(64)
                    .HasDefaultValueSql("('')");

                entity.Property(e => e.LastLoginTime).HasColumnType("datetime");

                entity.Property(e => e.LastName)
                    .IsRequired()
                    .HasMaxLength(64)
                    .HasDefaultValueSql("('')");

                entity.Property(e => e.LoginId)
                    .IsRequired()
                    .HasColumnName("LoginID")
                    .HasMaxLength(128);

                entity.Property(e => e.Password)
                    .IsRequired()
                    .HasMaxLength(64)
                    .IsUnicode(false);

                addAuditingProperties(entity);
            });
        }

        private void addAuditingProperties(EntityTypeBuilder builder)
        {
            builder.Property<DateTime>("CreatedTime")
                    .HasColumnType("datetime")
                    .HasDefaultValueSql("(getdate())");
            builder.Property<DateTime>("LastUpdatedTime")
                    .HasColumnType("datetime")
                    .HasDefaultValueSql("(getdate())");
        }

        //should be invoke somewhere...but I don't know...
        private void setAuditingPropertyValues(EntityEntry entityEntry)
        {
            PropertyEntry propertyEntry;
            if (
                 ((propertyEntry = entityEntry.Properties.Where(e => e.Metadata.Name == "CreatedTime").FirstOrDefault()) != null) &&
                           (entityEntry.State == EntityState.Added)
                          )
            {
                propertyEntry.CurrentValue = DateTime.UtcNow;
            }
            if (
                 ((propertyEntry = entityEntry.Properties.Where(e => e.Metadata.Name == "LastUpdatedTime").FirstOrDefault()) != null) &&
                          ((entityEntry.State == EntityState.Modified) || (entityEntry.State == EntityState.Added))
                         )
            {
                propertyEntry.CurrentValue = DateTime.UtcNow;
            }
        }
    }
}
